package com.zzj.service;

import cn.hutool.core.collection.ConcurrentHashSet;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.zzj.base.Result;
import com.zzj.entity.User;
import com.zzj.utils.Utils;
import io.netty.channel.Channel;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;


@Service
public class WebSocketService {

    private static final Integer LOGIN_CODE_LEN = 12;

    // 所有连接的用户
    private static final ConcurrentHashSet<Channel> CONNECTED_MAP = new ConcurrentHashSet<>();
    // 在线用户
    private static final ConcurrentHashMap<Channel, User> ONLINE_MAP = new ConcurrentHashMap<>();
    // 用户未登录状态 请求登录 发送登录码
    private static final ConcurrentHashMap<Channel, String> LOGGING_IN_MAP = new ConcurrentHashMap<>();


    /**
     * 用户未登录状态 单纯连接
     */
    public void connect(Channel channel) {
        CONNECTED_MAP.add(channel);  //加入连接
    }


    /**
     * 用户未登录状态 单纯断开
     */
    public void removed(Channel channel) {
        CONNECTED_MAP.remove(channel);  //移除连接
        ONLINE_MAP.remove(channel);     //移除在线
        LOGGING_IN_MAP.remove(channel); //移除登录中
    }
    /**
     * 添加用户在线
     *
     * @param channel
     * @param user
     */
    public void addOnline(Channel channel, User user) {
        ONLINE_MAP.put(channel, user);  // 添加在线
    }

    /**
     * 移除用户在线
     *
     * @param user
     */

    public void removeOnline(User user) {
        ONLINE_MAP.entrySet().removeIf(entry -> entry.getValue().getId().equals(user.getId())); // 移除在线
    }


    /**
     * 用户正在登录 查看登录码是否有效
     *
     * @param loginCode 登录码
     * @return
     */
    public boolean isLoggingIn(String loginCode) {
        return LOGGING_IN_MAP.containsValue(loginCode);
    }


    /**
     * 用户成功登录
     *
     * @param loginCode
     */
    public void loginSuccess(String loginCode, User user, Result<?> result) {
        Map.Entry<Channel, String> entry = null;
        for (Map.Entry<Channel, String> tmp : LOGGING_IN_MAP.entrySet()) {
            if (loginCode.equals(tmp.getValue())) {
                entry = tmp;
                break;
            }
        }
        if (entry != null) {
            Channel channel = entry.getKey();
            LOGGING_IN_MAP.remove(channel);  //移除登录中
            ONLINE_MAP.put(channel, user);  //已经登录用户绑定 Websocket连接
            sendMsg(channel, result);
        }
    }

    /**
     * 用户未登录状态 请求登录 生成登录码
     *
     * @param channel
     */
    public void handleUserLoginReq(Channel channel) {
        String s = Utils.generateRandomLoginCode(LOGIN_CODE_LEN);
        LOGGING_IN_MAP.put(channel, s); //请求登录的用户
        sendMsg(channel, Result.success("WS请求登录", s));
    }

    /**
     * 推送消息
     *
     * @param channel 连接
     * @param result
     */
    public void sendMsg(Channel channel, Result<?> result) {
        channel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(result)));
    }

    /**
     * 推送消息给所有连接用户
     *
     * @param result
     */
    public void sendToAllConnect(Result<?> result) {
        CONNECTED_MAP.forEach((channel) -> {
            sendMsg(channel, result);
        });
    }

    /**
     * 推送消息给所有在线用户
     *
     * @param result
     */
    public void sendToAllOnline(Result<?> result) {
        sendToAllOnline(result, null);
    }

    /**
     * 推送消息给所有在线用户 除了skipUid
     *
     * @param result
     * @param skipId
     */
    public void sendToAllOnline(Result<?> result, Integer skipId) {
        ONLINE_MAP.forEach((channel, channelData) -> {
            if (ObjectUtil.equal(channelData.getId(), skipId)) {
                return;
            }
            sendMsg(channel, result);
        });
    }
}
